/*
  KeePass Password Safe - The Open-Source Password Manager
  Copyright (C) 2003-2011 Dominik Reichl <dominik.reichl@t-online.de>

  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 2 of the License, or
  (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/

#include "StdAfx.h"
#include "PwManager.h"
#include "../Common/Crypto/ARCFour.h"
#include "Util/KeyTransform.h"
#include "Util/MemoryProtectionEx.h"
#include "Util/Base64.h"
#include "Util/PwUtil.h"
#include "Util/MemUtil.h"
#include "Util/StrUtil.h"
//#include "Util/TranslateEx.h"
#include "Util/ComUtil.h"
#include "../Common/Crypto/TwofishClass.h"

//#include <boost/static_assert.hpp>

//static PW_TIME g_pwTimeNever = { 2999, 12, 28, 23, 59, 59 };
static char g_pNullString[4] = { 0, 0, 0, 0 };

static bool g_bMetaInfoCvt = true;
static std_string g_strFindCachedString;
static std::vector<std_string> g_vFindCachedSplitted;

CPwManager::CPwManager()
{
	m_pEntries = NULL;

	m_pLastEditedEntry = NULL;
	m_nAlgorithm = ALGO_AES;
	m_dwKeyEncRounds = PWM_STD_KEYENCROUNDS;
	m_dbLastHeader = NULL;
	m_random.GetRandomBuffer(m_pSessionKey, PWM_SESSION_KEY_SIZE);

	mem_erase(m_pMasterKey, 32);
	mem_erase(m_pTransformedMasterKey, 32);
	m_strKeySource.clear();

	m_bUseTransactedFileWrites = FALSE;

	m_clr = DWORD_MAX;


}

CPwManager::~CPwManager()
{
	this->CleanUp();
}

void CPwManager::InitPrimaryInstance()
{
	ATLASSERT((m_pLastEditedEntry == NULL) && (memcmp(m_pMasterKey, g_pNullString, 4) == 0));
	ATLASSERT((m_nAlgorithm == ALGO_AES) && (m_dwKeyEncRounds == PWM_STD_KEYENCROUNDS));

	DWORD vInitXorShift[4];
	m_random.GetRandomBuffer((BYTE *)&vInitXorShift[0], 16);
	srandXorShift(vInitXorShift);

	//BOOST_STATIC_ASSERT(sizeof(BYTE) == 1);
	//BOOST_STATIC_ASSERT(sizeof(DWORD) == 4);
}


// DWORD CPwManager::Find(const TCHAR *pszFindString, BOOL bCaseSensitive,
//	DWORD searchFlags, DWORD nStart)
// {
//	return this->Find(pszFindString, bCaseSensitive, searchFlags, nStart, DWORD_MAX);
// }

DWORD CPwManager::Find(const TCHAR *pszFindString, BOOL bCaseSensitive,
	DWORD searchFlags, DWORD nStart, DWORD nEndExcl)
{
	

	if(nStart >= nEndExcl) return DWORD_MAX;
	/*ATLASSERT(pszFindString != NULL); if(pszFindString == NULL) return DWORD_MAX;

	CString strFind = pszFindString;
	if((strFind.GetLength() == 0) || (strFind == _T("*"))) return nStart;

	scoped_ptr<boost::basic_regex<TCHAR> > spRegex;
#ifndef _WIN64
	if((searchFlags & PWMS_REGEX) != 0)
	{
		try
		{
			if(bCaseSensitive == FALSE)
				spRegex.reset(new boost::basic_regex<TCHAR>((LPCTSTR)strFind,
					boost::regex_constants::icase));
			else
				spRegex.reset(new boost::basic_regex<TCHAR>((LPCTSTR)strFind));
		}
		catch(...) { return DWORD_MAX; }
	}
#else
#pragma message("No regular expression support in x64 library.")
#endif

	LPCTSTR lpSearch = strFind;
	if(bCaseSensitive == FALSE)
	{
		strFind = strFind.MakeLower();
		lpSearch = strFind;
	}

	for(DWORD i = nStart; i < nEndExcl; ++i)
	{
		if((searchFlags & PWMF_TITLE) != 0)
		{
			if(StrMatchText(m_pEntries[i].pszTitle, lpSearch, bCaseSensitive, spRegex.get()))
				return i;
		}

		if((searchFlags & PWMF_USER) != 0)
		{
			if(StrMatchText(m_pEntries[i].pszUserName, lpSearch, bCaseSensitive, spRegex.get()))
				return i;
		}

		if((searchFlags & PWMF_URL) != 0)
		{
			if(StrMatchText(m_pEntries[i].pszURL, lpSearch, bCaseSensitive, spRegex.get()))
				return i;
		}

		if((searchFlags & PWMF_PASSWORD) != 0)
		{
			UnlockEntryPassword(&m_pEntries[i]);
			CString strPassword = m_pEntries[i].pszPassword;
			LockEntryPassword(&m_pEntries[i]);

			if(StrMatchText(strPassword, lpSearch, bCaseSensitive, spRegex.get()))
			{
				EraseCString(&strPassword);
				return i;
			}

			EraseCString(&strPassword);
		}

		if((searchFlags & PWMF_ADDITIONAL) != 0)
		{
			if(StrMatchText(m_pEntries[i].pszAdditional, lpSearch, bCaseSensitive, spRegex.get()))
				return i;
		}

		if((searchFlags & PWMF_GROUPNAME) != 0)
		{
			const DWORD dwGroupIndex = GetGroupByIdN(m_pEntries[i].uGroupId);
			ATLASSERT(dwGroupIndex != DWORD_MAX);
			if(dwGroupIndex == DWORD_MAX) continue;

			if(StrMatchText(GetGroup(dwGroupIndex)->pszGroupName, lpSearch,
				bCaseSensitive, spRegex.get()))
				return i;
		}

		if((searchFlags & PWMF_UUID) != 0)
		{
			CString strUuid;
			_UuidToString(m_pEntries[i].uuid, &strUuid);

			if(StrMatchText(strUuid, lpSearch, bCaseSensitive, spRegex.get()))
				return i;
		}
	}*/

	return DWORD_MAX;
}

DWORD CPwManager::FindEx(const TCHAR *pszFindString, BOOL bCaseSensitive,
	DWORD searchFlags, DWORD nStart)
{
	if(((searchFlags & PWMS_REGEX) != 0) || (pszFindString == NULL) ||
		(pszFindString[0] == 0))
		return this->Find(pszFindString, bCaseSensitive, searchFlags, nStart, DWORD_MAX);

	const std_string strText = pszFindString;
	if(strText != g_strFindCachedString)
	{
		g_vFindCachedSplitted = SU_SplitSearchTerms(strText.c_str());
		g_strFindCachedString = strText;
	}
	const std::vector<std_string>* pvTerms = &g_vFindCachedSplitted;

	if(pvTerms->size() == 0) return nStart;

	DWORD dwIndex = nStart;
	while(dwIndex != DWORD_MAX)
	{
		bool bAllMatch = true;
		for(size_t i = 0; i < pvTerms->size(); ++i)
		{
			const std_string& strTerm = (*pvTerms)[i];
			const DWORD dwRes = this->Find(strTerm.c_str(), bCaseSensitive,
				searchFlags, dwIndex, DWORD_MAX);

			if(dwRes > dwIndex)
			{
				dwIndex = dwRes;
				bAllMatch = false;
				break;
			}
		}

		if(bAllMatch) break;
	}

	return dwIndex;
}

void CPwManager::CleanUp()
{
	_DeleteEntryList(TRUE);

	m_pLastEditedEntry = NULL;
	if(NULL != m_dbLastHeader)
		delete m_dbLastHeader;
	mem_erase(m_pMasterKey, 32);
	mem_erase(m_pTransformedMasterKey, 32);
	m_strKeySource.clear();

	m_bUseTransactedFileWrites = FALSE;

	m_clr = DWORD_MAX;

	m_strDefaultUserName.clear();
	m_vSearchHistory.clear();
	m_vCustomKVPs.clear();
}

int CPwManager::SetMasterKey(const TCHAR *pszMasterKey, BOOL bDiskDrive,
	const TCHAR *pszSecondKey, const CNewRandomInterface *pARI, BOOL bOverwrite,
	const TCHAR *pszProviderName)
{
	size_t uKeyLen2 = 0, uFileSize, uRead;
	TCHAR szFile[2048];
	sha256_ctx sha32;
	char *paKey = NULL;
	char *paKey2 = NULL;
	unsigned char aFileKey[32];
	unsigned char aPasswordKey[32];
	bool bReadNormal;
	std::vector<BYTE> vExtKey;
	if(pszSecondKey != NULL)
		m_dbLastHeader->m_KeyFile = CString(pszMasterKey);
	ATLASSERT(pszMasterKey != NULL); if(pszMasterKey == NULL) return PWE_INVALID_PARAM;

#ifdef _UNICODE
	//BOOST_STATIC_ASSERT(sizeof(TCHAR) >= 2);
	paKey = _StringToAnsi(pszMasterKey);
#else
	BOOST_STATIC_ASSERT(sizeof(TCHAR) == 1);
	size_t sizeANSIKeyBuffer = _tcslen(pszMasterKey) + 1;
	paKey = new char[sizeANSIKeyBuffer];
	ATLASSERT(paKey != NULL); if(paKey == NULL) return PWE_NO_MEM;
	strcpy_s(paKey, sizeANSIKeyBuffer, pszMasterKey);
#endif

	ATLASSERT(paKey != NULL); if(paKey == NULL) return PWE_NO_MEM;

	if(pszSecondKey != NULL)
	{
#ifdef _UNICODE
		//BOOST_STATIC_ASSERT(sizeof(TCHAR) >= 2);
		paKey2 = _StringToAnsi(pszSecondKey);
#else
		BOOST_STATIC_ASSERT(sizeof(TCHAR) == 1);
		size_t sizeByteBuffer = _tcslen(pszSecondKey) + 1;
		paKey2 = new char[sizeByteBuffer];
		ATLASSERT(paKey2 != NULL); if(paKey2 == NULL) return PWE_NO_MEM;
		strcpy_s(paKey2, sizeByteBuffer, pszSecondKey);
#endif

		ATLASSERT(paKey2 != NULL); if(paKey2 == NULL) return PWE_NO_MEM;

		uKeyLen2 = szlen(paKey2);
		ATLASSERT(uKeyLen2 != 0);
	}

	const size_t uKeyLen = strlen(paKey);
	ATLASSERT(uKeyLen != 0);
	if(uKeyLen == 0) { SAFE_DELETE_ARRAY(paKey); return PWE_INVALID_KEY; }

	std::basic_string<TCHAR> strKeySourceCand;

	if(bDiskDrive == FALSE)
	{
		sha256_begin(&sha32);
		sha256_hash((unsigned char *)paKey, static_cast<unsigned long>(uKeyLen),
			&sha32);
		sha256_end((unsigned char *)m_pMasterKey, &sha32);
		ProtectMasterKey(true);
		m_strKeySource.clear();

		mem_erase((unsigned char *)paKey, uKeyLen);
		SAFE_DELETE_ARRAY(paKey);
		return PWE_SUCCESS;
	}
	else if(CBase64Codec::IsBase64UrlStringT(pszMasterKey))
	{
		mem_erase((unsigned char *)paKey, uKeyLen);
		SAFE_DELETE_ARRAY(paKey); // Don't need ASCII key any more from on now

		const bool bDec64 = CBase64Codec::DecodeUrlT(pszMasterKey, vExtKey);
		if(bDec64 && (vExtKey.size() > 0))
		{
			sha256_begin(&sha32);
			sha256_hash(&vExtKey[0], static_cast<unsigned long>(vExtKey.size()), &sha32);
			sha256_end((unsigned char *)aFileKey, &sha32);
		}
		else return PWE_KEYPROV_INVALID_KEY;
		mem_erase(&vExtKey[0], vExtKey.size());

		if(pszProviderName != NULL) m_strKeySource = pszProviderName;
		else { ATLASSERT(FALSE); m_strKeySource.clear(); }

		if(pszSecondKey == NULL) // External source only
		{
			memcpy(m_pMasterKey, aFileKey, 32);
			ProtectMasterKey(true);
			mem_erase((unsigned char *)aFileKey, 32);
			return PWE_SUCCESS;
		}
		else // pszSecondKey != NULL
		{
			sha256_begin(&sha32);
			sha256_hash((unsigned char *)paKey2,
				static_cast<unsigned long>(uKeyLen2), &sha32);
			sha256_end((unsigned char *)aPasswordKey, &sha32);

			mem_erase((unsigned char *)paKey2, uKeyLen2);
			SAFE_DELETE_ARRAY(paKey);

			sha256_begin(&sha32);
			sha256_hash(aPasswordKey, 32, &sha32);
			sha256_hash(aFileKey, 32, &sha32);
			sha256_end((unsigned char *)m_pMasterKey, &sha32);
			ProtectMasterKey(true);

			mem_erase((unsigned char *)aPasswordKey, 32);
			mem_erase((unsigned char *)aFileKey, 32);
			return PWE_SUCCESS;
		}
	}
	else // With key file
	{
		mem_erase((unsigned char *)paKey, uKeyLen);
		SAFE_DELETE_ARRAY(paKey); // Don't need ASCII key any more from on now
		m_dbLastHeader->m_PswAndKey = 1;
		if(pszSecondKey == NULL) // Key file only
		{
			_tcscpy_s(szFile, _countof(szFile), pszMasterKey);
			if(szFile[_tcslen(szFile) - 1] == _T('\\'))
				_tcscat_s(szFile, _countof(szFile), PWS_DEFAULT_KEY_FILENAME);
			strKeySourceCand = szFile;

			if(pARI == NULL) // If pARI is NULL: load key from disk
			{
				FILE *fp = NULL;
				_tfopen_s(&fp, szFile, _T("rb"));
				if(fp == NULL) return PWE_NOFILEACCESS_READ_KEY;
				fseek(fp, 0, SEEK_END);
				uFileSize = (unsigned long)ftell(fp);
				fseek(fp, 0, SEEK_SET);

				bReadNormal = true;

				if(uFileSize == 32)
				{
					if(fread(m_pMasterKey, 1, 32, fp) != 32)
					{
						fclose(fp); fp = NULL;
						return PWE_FILEERROR_READ;
					}

					ProtectMasterKey(true);
					bReadNormal = false;
				}
				else if(uFileSize == 64)
				{
					if(CPwUtil::LoadHexKey32(fp, m_pMasterKey) == FALSE)
						fseek(fp, 0, SEEK_SET);
					else
					{
						ProtectMasterKey(true);
						bReadNormal = false;
					}
				}

				if(bReadNormal)
				{
					sha256_begin(&sha32);
					while(1)
					{
						uRead = (unsigned long)fread((unsigned char *)szFile, 1, 2048, fp);
						if(uRead == 0) break;
						sha256_hash((unsigned char *)szFile,
							static_cast<unsigned long>(uRead), &sha32);
						if(uRead != 2048) break;
					}
					sha256_end((unsigned char *)m_pMasterKey, &sha32);
					ProtectMasterKey(true);
				}

				m_strKeySource = strKeySourceCand;
				fclose(fp); fp = NULL;
				return PWE_SUCCESS;
			}
			else // pARI is not NULL: save key to disk
			{
				FILE *fp = NULL;
				unsigned char aRandomBytes[32];

				_tfopen_s(&fp, szFile, _T("rb")); // Does the file exist already?
				if((fp != NULL) && (bOverwrite == FALSE))
				{
					fclose(fp); fp = NULL;
					return PWE_NOFILEACCESS_READ_KEY;
				}
				if(fp != NULL) { fclose(fp); fp = NULL; } // We must close it before opening for write

				if(pARI->GenerateRandomSequence(32, aRandomBytes) == FALSE) return PWE_INVALID_RANDOMSOURCE;

				fp = NULL;
				_tfopen_s(&fp, szFile, _T("wb"));
				if(fp == NULL) return PWE_NOFILEACCESS_WRITE;
				if(CPwUtil::SaveHexKey32(fp, aRandomBytes) == FALSE)
				{
					fclose(fp); fp = NULL;
					return PWE_FILEERROR_WRITE;
				}
				fclose(fp); fp = NULL;

				memcpy(m_pMasterKey, aRandomBytes, 32);
				ProtectMasterKey(true);
				m_strKeySource = strKeySourceCand;
				return PWE_SUCCESS;
			}
		}
		else // pszSecondKey != NULL
		{
			_tcscpy_s(szFile, _countof(szFile), pszMasterKey);
			if(szFile[_tcslen(szFile) - 1] == _T('\\'))
				_tcscat_s(szFile, _countof(szFile), PWS_DEFAULT_KEY_FILENAME);
			strKeySourceCand = szFile;

			if(pARI == NULL) // If pARI is NULL: load key from disk
			{
				FILE *fp = NULL;
				_tfopen_s(&fp, szFile, _T("rb"));
				if(fp == NULL) return PWE_NOFILEACCESS_READ_KEY;
				fseek(fp, 0, SEEK_END);
				uFileSize = (unsigned long)ftell(fp);
				fseek(fp, 0, SEEK_SET);

				bReadNormal = true;

				if(uFileSize == 32)
				{
					if(fread(aFileKey, 1, 32, fp) != 32)
					{
						fclose(fp); fp = NULL;
						return PWE_FILEERROR_READ;
					}

					bReadNormal = false;
				}
				else if(uFileSize == 64)
				{
					if(CPwUtil::LoadHexKey32(fp, aFileKey) == FALSE)
						fseek(fp, 0, SEEK_SET);
					else bReadNormal = false;
				}

				if(bReadNormal)
				{
					sha256_begin(&sha32);
					while(1)
					{
						uRead = (unsigned long)fread((unsigned char *)szFile, 1, 2048, fp);
						if(uRead == 0) break;
						sha256_hash((unsigned char *)szFile,
							static_cast<unsigned long>(uRead), &sha32);
						if(uRead != 2048) break;
					}
					sha256_end((unsigned char *)aFileKey, &sha32);
				}

				fclose(fp); fp = NULL;

				sha256_begin(&sha32);
				sha256_hash((unsigned char *)paKey2,
					static_cast<unsigned long>(uKeyLen2), &sha32);
				sha256_end((unsigned char *)aPasswordKey, &sha32);

				mem_erase((unsigned char *)paKey2, uKeyLen2);
				SAFE_DELETE_ARRAY(paKey);

				sha256_begin(&sha32);
				sha256_hash(aPasswordKey, 32, &sha32);
				sha256_hash(aFileKey, 32, &sha32);
				sha256_end((unsigned char *)m_pMasterKey, &sha32);
				ProtectMasterKey(true);

				mem_erase((unsigned char *)aPasswordKey, 32);
				mem_erase((unsigned char *)aFileKey, 32);
				m_strKeySource = strKeySourceCand;
				return PWE_SUCCESS;
			}
			else // pARI is not NULL: save key to disk
			{
				FILE *fp = NULL;
				unsigned char aRandomBytes[32];

				_tfopen_s(&fp, szFile, _T("rb")); // Does the file exist already?
				if((fp != NULL) && (bOverwrite == FALSE))
				{
					fclose(fp); fp = NULL;
					return PWE_NOFILEACCESS_READ_KEY;
				}
				if(fp != NULL) { fclose(fp); fp = NULL; } // We must close it before opening for write

				if(pARI->GenerateRandomSequence(32, aRandomBytes) == FALSE) return PWE_INVALID_RANDOMSOURCE;

				_tfopen_s(&fp, szFile, _T("wb"));
				if(fp == NULL) return PWE_NOFILEACCESS_WRITE;
				if(CPwUtil::SaveHexKey32(fp, aRandomBytes) == FALSE)
				{
					fclose(fp); fp = NULL;
					return PWE_FILEERROR_WRITE;
				}
				fclose(fp); fp = NULL;

				ATLASSERT(uKeyLen2 != 0);
				sha256_begin(&sha32);
				sha256_hash((unsigned char *)paKey2,
					static_cast<unsigned long>(uKeyLen2), &sha32);
				sha256_end((unsigned char *)aPasswordKey, &sha32);

				mem_erase((unsigned char *)paKey2, uKeyLen2);
				SAFE_DELETE_ARRAY(paKey);

				sha256_begin(&sha32);
				sha256_hash(aPasswordKey, 32, &sha32);
				sha256_hash(aRandomBytes, 32, &sha32);
				sha256_end((unsigned char *)m_pMasterKey, &sha32);
				ProtectMasterKey(true);

				mem_erase((unsigned char *)aPasswordKey, 32);
				mem_erase((unsigned char *)aFileKey, 32);
				m_strKeySource = strKeySourceCand;
				return PWE_SUCCESS;
			}
		}
	}

	// return PWE_UNKNOWN; // Unreachable anyway
}
void CPwManager::GetNeverExpireTime(__out_ecount(1) CTime& pPwTime)
{
	if(pPwTime == NULL) return;
	pPwTime = CTime(2999,12,30,12,59,59);
	//memcpy(pPwTime, &g_pwTimeNever, sizeof(PW_TIME));
}

void CPwManager::NewDatabase()
{
	_DeleteEntryList(TRUE); // Delete really everything, the strings too
	//_DeleteGroupList(TRUE);
	m_pEntries = new PswPfList();
	m_pLastEditedEntry = NULL;
	if(NULL != m_dbLastHeader )
	{
		delete m_dbLastHeader;
		m_dbLastHeader = NULL;
	}
	m_dbLastHeader = new CPwMaster();
	// Do not clear keys here!
	// mem_erase(m_pMasterKey, 32);
	// mem_erase(m_pTransformedMasterKey, 32);

	m_vUnknownMetaStreams.clear();

	m_strDefaultUserName.clear();
	m_vSearchHistory.clear();
	m_vCustomKVPs.clear();

	m_clr = DWORD_MAX;
}

int CPwManager::GetAlgorithm() const
{
	return m_nAlgorithm;
}

BOOL CPwManager::SetAlgorithm(int nAlgorithm)
{
	ATLASSERT((nAlgorithm == ALGO_AES) || (nAlgorithm == ALGO_TWOFISH));
	if((nAlgorithm != ALGO_AES) && (nAlgorithm != ALGO_TWOFISH)) return FALSE;

	m_nAlgorithm = nAlgorithm;
	return TRUE;
}


void CPwManager::_DeleteEntryList(BOOL bFreeStrings)
{
	if(m_pEntries == NULL) return; // Nothing to delete

	if(bFreeStrings == TRUE)
	{
		POSITION Pos = m_pEntries->GetHeadPosition();

			while (Pos != NULL) {
				CPasswordProfile * pPd= m_pEntries->GetNext(Pos);
				delete pPd;
			}   
			delete m_pEntries;
			m_pEntries = NULL;
	}
}


CPasswordProfile *CPwManager::GetEntry(DWORD dwIndex)
{
	// ATLASSERT(dwIndex < m_dwNumEntries);
	if(dwIndex >= m_pEntries->GetCount()) return NULL;
	POSITION pos = m_pEntries->FindIndex(dwIndex);
	if(pos == NULL)
		return NULL;
	return m_pEntries->GetAt(pos);
}

CPasswordProfile *CPwManager::GetEntryByGroup(DWORD idGroup, DWORD dwIndex)
{


	return GetEntryByGroupN(idGroup, dwIndex);
}

CPasswordProfile* CPwManager::GetEntryByGroupN(DWORD idGroup, DWORD dwIndex) const
{
	ATLASSERT(idGroup != DWORD_MAX);
	if(idGroup == DWORD_MAX) return NULL;
	if(dwIndex >= m_pEntries->GetCount()) return NULL;
	POSITION Pos = m_pEntries->GetHeadPosition();
	
	do {
		CPasswordProfile * pPd= m_pEntries->GetNext(Pos);
		if(pPd->m_nClassID == idGroup)
			return pPd;
	} while (Pos != NULL);
	
	return NULL;
}

CPasswordProfile *CPwManager::GetLastEditedEntry()
{
	return m_pLastEditedEntry;
}


BOOL CPwManager::AddEntry( CPasswordProfile *pTemplate)
{
	// Don't ASSERT_ENTRY the pTemplate!
	ATLASSERT(pTemplate != NULL); if(pTemplate == NULL) return FALSE;
	ATLASSERT((pTemplate->m_nClassID != 0) && (pTemplate->m_nClassID != DWORD_MAX));
	if((pTemplate->m_nClassID == 0) || (pTemplate->m_nClassID == DWORD_MAX)) return FALSE;
	//CPasswordManager pswMgr;
	//int res = pswMgr.Add(*pTemplate);
	//if(res == 63)
	//{
	pTemplate->m_nUNLen = _tcslen(pTemplate->m_strUserName);
	pTemplate->m_nPswLen = _tcslen(pTemplate->m_strPassword);
	LockEntryPassword(pTemplate);
	m_pEntries->AddTail(pTemplate);
	m_pLastEditedEntry = pTemplate;
		//return TRUE;
	//}
	//else
	//return FALSE;
	return TRUE;
}

BOOL CPwManager::DeleteEntry( CPasswordProfile *pEntry)
{
	if(NULL == pEntry)
		return FALSE;
	
	POSITION pos= m_pEntries->GetHeadPosition();
	if(pos == NULL)
		return FALSE;
	BOOL bRes = FALSE;
	POSITION curPos = pos;
	while(NULL != pos)
	{
		CPasswordProfile *pTemplate = m_pEntries->GetNext(pos);
		if(pTemplate->m_nID == pEntry->m_nID && pTemplate->m_nClassID == pEntry->m_nClassID && pTemplate->m_nMasterID == pEntry->m_nMasterID)
		{
			m_pEntries->RemoveAt(curPos);
			delete pTemplate;
			 bRes = TRUE;
			break;
		}
		curPos = pos;
	}
	return bRes;
	/*CPasswordManager pswMgr;
	int bRes= pswMgr.Delete(pTemplate->m_nID);
	if(bRes == 65)
	{
		m_pEntries->RemoveAt(pos);
		delete pTemplate;
		return TRUE;
	}
	else
		return FALSE;*/
}



void CPwManager::LockEntryPassword(__inout_ecount(1) CPasswordProfile *pEntry)
{
	if(pEntry == NULL) return;
	if(pEntry->m_strPassword.IsEmpty()) return;
	if(pEntry->m_strPassword.IsEmpty()) return;
	// Use DPAPI for advanced memory protection, if available and enabled
	HRESULT Res =CMemoryProtectionEx::EncryptText((LPTSTR)(LPCTSTR)(pEntry->m_strPassword),
		pEntry->m_strPassword.GetLength());
	if(Res == S_OK && (CMemoryProtectionEx::EncryptText((LPTSTR)(LPCTSTR)(pEntry->m_strUserName),
		pEntry->m_strUserName.GetLength()) == S_OK)) return;

	// ARCFour is self-inverse, see UnlockEntryPassword
	if(pEntry->m_strPassword.GetLength() != 0)
	{
		BYTE* pb = (BYTE*) pEntry->m_strPassword.GetBuffer(pEntry->m_strPassword.GetLength());
		ARCFourCrypt(pb, pEntry->m_strPassword.GetLength() * sizeof(TCHAR),
			m_pSessionKey, PWM_SESSION_KEY_SIZE);
		pEntry->m_strPassword.ReleaseBuffer();
	}
	if(pEntry->m_strUserName.GetLength() != 0)
	{
		BYTE* pb = (BYTE*) pEntry->m_strUserName.GetBuffer(pEntry->m_strUserName.GetLength());
		ARCFourCrypt(pb, pEntry->m_strUserName.GetLength() * sizeof(TCHAR),
			m_pSessionKey, PWM_SESSION_KEY_SIZE);
		pEntry->m_strUserName.ReleaseBuffer();
	}
	//ATLASSERT(pEntry->pszPassword[pEntry->uPasswordLen] == 0);
}

void CPwManager::UnlockEntryPassword(__inout_ecount(1) CPasswordProfile *pEntry)
{
	if(pEntry == NULL) return;
	if(pEntry->m_strUserName.IsEmpty()) return;
	if(pEntry->m_strPassword.IsEmpty()) return;
	HRESULT Res =CMemoryProtectionEx::DecryptText((LPTSTR)(LPCTSTR)(pEntry->m_strPassword),
		pEntry->m_strPassword.GetLength());
	// Use DPAPI for advanced memory protection, if available and enabled
	if( Res == S_OK && CMemoryProtectionEx::DecryptText((LPTSTR)(LPCTSTR)(pEntry->m_strUserName),
		pEntry->m_strUserName.GetLength()) == S_OK) return;

	// ARCFour is self-inverse, see LockEntryPassword
	if(pEntry->m_strPassword.GetLength() != 0)
	{
		BYTE* pB = (BYTE*) pEntry->m_strPassword.GetBuffer(pEntry->m_strPassword.GetLength());
		ARCFourCrypt(pB, pEntry->m_strPassword.GetLength() * sizeof(TCHAR),
			m_pSessionKey, PWM_SESSION_KEY_SIZE);
		pEntry->m_strPassword.ReleaseBuffer();
	}
	if(pEntry->m_strUserName.GetLength() != 0)
	{
		BYTE* pB = (BYTE*) pEntry->m_strUserName.GetBuffer(pEntry->m_strUserName.GetLength());
		ARCFourCrypt(pB, pEntry->m_strUserName.GetLength() * sizeof(TCHAR),
			m_pSessionKey, PWM_SESSION_KEY_SIZE);
		pEntry->m_strUserName.ReleaseBuffer();
	}
	//ATLASSERT(static_cast<DWORD>(_tcslen(pEntry->pszPassword)) == pEntry->uPasswordLen);
}

void CPwManager::ProtectMasterKey(bool bProtectKey)
{
	if(bProtectKey)
	{
		if(CMemoryProtectionEx::EncryptMemory(m_pMasterKey, 32) == S_OK) return;
	}
	else // Unprotect
	{
		if(CMemoryProtectionEx::DecryptMemory(m_pMasterKey, 32) == S_OK) return;
	}

	// Works for both encryption and decryption
	ARCFourCrypt(m_pMasterKey, 32, m_pSessionKey, PWM_SESSION_KEY_SIZE);
}

void CPwManager::ProtectTransformedMasterKey(bool bProtectKey)
{
	if(bProtectKey)
	{
		if(CMemoryProtectionEx::EncryptMemory(m_pTransformedMasterKey, 32) == S_OK) return;
	}
	else // Unprotect
	{
		if(CMemoryProtectionEx::DecryptMemory(m_pTransformedMasterKey, 32) == S_OK) return;
	}

	// Works for both encryption and decryption
	ARCFourCrypt(m_pTransformedMasterKey, 32, m_pSessionKey, PWM_SESSION_KEY_SIZE);
}




// Encrypt the master key a few times to make brute-force key-search harder
BOOL CPwManager::_TransformMasterKey(const BYTE *pKeySeed)
{
	const UINT8 aRef[16] = { // Expected ciphertext
		0x8e, 0xa2, 0xb7, 0xca, 0x51, 0x67, 0x45, 0xbf,
		0xea, 0xfc, 0x49, 0x90, 0x4b, 0x49, 0x60, 0x89
	};
	DWORD i;

	ATLASSERT(pKeySeed != NULL); if(pKeySeed == NULL) return FALSE;

	CRijndael rijndael;
	if(rijndael.Init(CRijndael::ECB, CRijndael::EncryptDir, (const UINT8 *)pKeySeed,
		CRijndael::Key32Bytes, 0) != RIJNDAEL_SUCCESS)
	{
		return FALSE;
	}

	ProtectMasterKey(false);
	memcpy(m_pTransformedMasterKey, m_pMasterKey, 32);
	ProtectMasterKey(true);

	if(CKeyTransform::Transform256(m_dwKeyEncRounds, m_pTransformedMasterKey,
		pKeySeed) == false)
	{

		for(i = 0; i < m_dwKeyEncRounds; ++i)
			rijndael.BlockEncrypt((const UINT8 *)m_pTransformedMasterKey, 256, (UINT8 *)m_pTransformedMasterKey);
	}

	// Do a quick test if the Rijndael class worked correctly
	UINT8 aKey[32];
	for(i = 0; i < 32; ++i) aKey[i] = static_cast<UINT8>(i);
	UINT8 aTest[16];
	for(i = 0; i < 16; ++i) aTest[i] = (UINT8)(((UINT8)i << 4) | (UINT8)i);
	if(rijndael.Init(CRijndael::ECB, CRijndael::EncryptDir, aKey, CRijndael::Key32Bytes, NULL) != RIJNDAEL_SUCCESS)
		{ ATLASSERT(FALSE); return FALSE; }
	if(rijndael.BlockEncrypt(aTest, 128, aTest) != 128) { ATLASSERT(FALSE); }
	if(memcmp(aTest, aRef, 16) != 0) { ATLASSERT(FALSE); return FALSE; }

	// Hash once with SHA-256
	sha256_ctx sha2;
	sha256_begin(&sha2);
	sha256_hash(m_pTransformedMasterKey, 32, &sha2);
	sha256_end(m_pTransformedMasterKey, &sha2);

	ProtectTransformedMasterKey(true);
	return TRUE;
}

DWORD CPwManager::GetKeyEncRounds() const
{
	return m_dwKeyEncRounds;
}

void CPwManager::SetKeyEncRounds(DWORD dwRounds)
{
	// All allowed except DWORD_MAX
	if(dwRounds == DWORD_MAX) m_dwKeyEncRounds = DWORD_MAX - 1;
	else m_dwKeyEncRounds = dwRounds;
}


/* DWORD CPwManager::MakeGroupTree(LPCTSTR lpTreeString, TCHAR tchSeparator)
{
	DWORD i, j = 0, dwCurGroup = 0, dwTestGroup;
	DWORD dwId = DWORD_MAX;
	TCHAR *ptzTemp;
	DWORD dwStrLen;
	DWORD dwLevel = 0;
	TCHAR tch;

	ATLASSERT(lpTreeString != NULL); if(lpTreeString == NULL) return DWORD_MAX;

	dwStrLen = static_cast<DWORD>(_tcslen(lpTreeString));
	ptzTemp = new TCHAR[dwStrLen + 1]; ATLASSERT(ptzTemp != NULL);
	ptzTemp[0] = 0;

	for(i = 0; i < (dwStrLen + 1); i++)
	{
		tch = lpTreeString[i];

		if((tch == tchSeparator) || (tch == 0))
		{
			ptzTemp[j] = 0;

			j = 0;
		}
		else
		{
			ptzTemp[j] = tch;
			j++;
		}
	}

	SAFE_DELETE_ARRAY(ptzTemp);
	return dwId;
} */


void CPwManager::GetRawMasterKey(__out_ecount(32) BYTE *pStorage)
{
	ATLASSERT(pStorage != NULL); if(pStorage == NULL) return;

	ProtectMasterKey(false);
	memcpy(pStorage, m_pMasterKey, 32);
	ProtectMasterKey(true);
}

void CPwManager::SetRawMasterKey(__in_ecount(32) const BYTE *pNewKey)
{
	if(pNewKey != NULL)
	{
		memcpy(m_pMasterKey, pNewKey, 32);
		ProtectMasterKey(true);
	}
	else mem_erase(m_pMasterKey, 32);
}

void CPwManager::ClearMasterKey(BOOL bClearKey, BOOL bClearTransformedKey)
{
	if(bClearKey == TRUE) mem_erase(m_pMasterKey, 32);
	if(bClearTransformedKey == TRUE) mem_erase(m_pTransformedMasterKey, 32);
}

LPCTSTR CPwManager::GetKeySource() const
{
	return m_strKeySource.c_str();
}

std::basic_string<TCHAR> CPwManager::GetPropertyString(DWORD dwPropertyId) const
{
	if(dwPropertyId == PWP_DEFAULT_USER_NAME)
		return m_strDefaultUserName;

	ATLASSERT(FALSE);
	return std::basic_string<TCHAR>();
}

BOOL CPwManager::SetPropertyString(DWORD dwPropertyId, LPCTSTR lpValue)
{
	ATLASSERT(lpValue != NULL); if(lpValue == NULL) return FALSE;

	BOOL bResult = TRUE;
	switch(dwPropertyId)
	{
		case PWP_DEFAULT_USER_NAME:
			m_strDefaultUserName = lpValue;
			break;
		default:
			ATLASSERT(FALSE);
			bResult = FALSE;
			break;
	}

	return bResult;
}

std::vector<std::basic_string<TCHAR> >* CPwManager::AccessPropertyStrArray(
	DWORD dwPropertyId)
{
	if(dwPropertyId == PWPA_SEARCH_HISTORY)
		return &m_vSearchHistory;

	ATLASSERT(FALSE);
	return NULL;
}

BYTE* CPwManager::SerializeCustomKvp(const CustomKvp& kvp)
{
	RC_QUERY q;
	q.strClientID = kvp.first;
	q.strCommand = kvp.second;

	RC_STRING str;
	if(RCPackQuery(str, q) == FALSE) { ATLASSERT(FALSE); return NULL; }

	return _StringToUTF8(str.c_str());
}

bool CPwManager::DeserializeCustomKvp(const BYTE *pStream, CustomKvp& kvpBuffer)
{
	LPCTSTR lpString = _UTF8ToString(pStream);
	if(lpString == NULL) { ATLASSERT(FALSE); return false; }

	bool bResult = true;
	RC_STRING str = lpString;
	RC_QUERY q;
	if(RCUnpackQuery(q, str) == FALSE) { ATLASSERT(FALSE); bResult = false; }

	if(bResult)
	{
		kvpBuffer.first = q.strClientID;
		kvpBuffer.second = q.strCommand;
	}

	SAFE_DELETE_ARRAY(lpString);
	return bResult;
}

// Passing NULL as lpValue deletes the specified key
BOOL CPwManager::SetCustomKvp(LPCTSTR lpKey, LPCTSTR lpValue)
{
	ATLASSERT(lpKey != NULL); if(lpKey == NULL) return FALSE;

	for(std::vector<CustomKvp>::iterator it = m_vCustomKVPs.begin();
		it != m_vCustomKVPs.end(); ++it)
	{
		if(_tcscmp(it->first.c_str(), lpKey) == 0)
		{
			if(lpValue == NULL) m_vCustomKVPs.erase(it);
			else it->second = lpValue;

			return TRUE;
		}
	}

	if(lpValue == NULL) return FALSE; // Failed to delete
	else
	{
		CustomKvp kvpNew;
		kvpNew.first = lpKey;
		kvpNew.second = lpValue;
		m_vCustomKVPs.push_back(kvpNew);
	}

	return TRUE;
}

LPCTSTR CPwManager::GetCustomKvp(LPCTSTR lpKey) const
{
	ATLASSERT(lpKey != NULL); if(lpKey == NULL) return NULL;

	for(std::vector<CustomKvp>::const_iterator it = m_vCustomKVPs.begin();
		it != m_vCustomKVPs.end(); ++it)
	{
		if(_tcscmp(it->first.c_str(), lpKey) == 0)
			return it->second.c_str();
	}

	return NULL;
}

COLORREF CPwManager::GetColor() const
{
	return m_clr;
}

void CPwManager::SetColor(COLORREF clr)
{
	m_clr = clr;
}
int CPwManager::OpenDatabase(CString strName)
{
	
	if(strName.IsEmpty())
		return -1;
	char *pUserName;
	char *pPassword;
	unsigned long uEncryptedUN,uEncryptedPsw;
	
	_DeleteEntryList(TRUE);

	m_pLastEditedEntry = NULL;
	if(NULL != m_dbLastHeader)
		delete m_dbLastHeader;

	sha256_ctx sha32;
	UINT8 uFinalKey[32];

	CPasswordManager pmm;
	m_dbLastHeader = pmm.Get(strName);
	if( NULL == m_dbLastHeader)
		return -1;
	//m_dbLastHeader = m_dbLastHeader;
	//memcpy(&m_dbLastHeader,m_dbLastHeader,sizeof(CPwMaster));

	m_dwKeyEncRounds = m_dbLastHeader->m_KeyEncRounds;

	// Generate m_pTransformedMasterKey from m_pMasterKey
	if(_TransformMasterKey(m_dbLastHeader->m_MasterSeed2) == FALSE) { ATLASSERT(FALSE); }

	ProtectTransformedMasterKey(false);

	// Hash the master password with the salt in the file
	sha256_begin(&sha32);
	sha256_hash(m_dbLastHeader->m_MasterSeed, 16, &sha32);
	sha256_hash(m_pTransformedMasterKey, 32, &sha32);
	sha256_end((unsigned char *)uFinalKey, &sha32);
	//NewDatabase(); // Create a new database and initialize internal structures
	CPasswordManager Pswm;
	this->m_pEntries = Pswm.Get(m_dbLastHeader->m_nID);
	
	if(NULL == m_pEntries || m_pEntries->GetCount() == 0)
		return -1;
	ProtectTransformedMasterKey(true);
	POSITION Pos = m_pEntries->GetHeadPosition();

	while (Pos != NULL)
	{
		CPasswordProfile * pPd= m_pEntries->GetNext(Pos);
		pUserName = new char[pPd->m_nUNLen];
		memset(pUserName,0,pPd->m_nUNLen);
		pPassword = new char[pPd->m_nPswLen];
		memset(pPassword,0,pPd->m_nPswLen);
		if(m_nAlgorithm == ALGO_AES)
		{
			CRijndael aes;
			// Initialize Rijndael algorithm
			if(aes.Init(CRijndael::CBC, CRijndael::DecryptDir, uFinalKey,
				CRijndael::Key32Bytes, m_dbLastHeader->m_EncryptionIV) != RIJNDAEL_SUCCESS)
				{ return PWE_CRYPT_ERROR; }
			
			// Decrypt! The first bytes aren't encrypted (that's the header)
			uEncryptedUN = (unsigned long)aes.PadDecrypt((UINT8 *)pPd->m_pUserName,
				pPd->m_nUNLen , (UINT8 *)pUserName);
			if(uEncryptedUN > 2147483446 || uEncryptedUN == 0)
			{
				return PWE_INVALID_KEY;
			}
			
			uEncryptedPsw = (unsigned long)aes.PadDecrypt((UINT8 *)pPd->m_pPassword,
				pPd->m_nPswLen , (UINT8 *)pPassword);
			if(uEncryptedPsw > 2147483446 || uEncryptedPsw == 0)
			{
				return PWE_INVALID_KEY;
			}

		}
		else if(m_nAlgorithm == ALGO_TWOFISH)
		{
			CTwofish twofish;
			if(twofish.Init(uFinalKey, 32, m_dbLastHeader->m_EncryptionIV) != true)
				{ return PWE_INVALID_FILESTRUCTURE; };
			uEncryptedUN = (unsigned long)twofish.PadDecrypt((UINT8 *)pPd->m_pUserName,
				pPd->m_nUNLen , (UINT8 *)pUserName);
			if(uEncryptedUN > 2147483446 || uEncryptedUN == 0)
			{
				return PWE_INVALID_KEY;
			}
			uEncryptedPsw = (unsigned long)twofish.PadDecrypt((UINT8 *)pPd->m_pPassword,
				pPd->m_nPswLen , (UINT8 *)pPassword);
			if(uEncryptedPsw > 2147483446 || uEncryptedPsw == 0)
			{
				return PWE_INVALID_KEY;
			}
		}

		// Check if key is correct (with very high probability)
		/*unsigned char vContentsHash[32];
		sha256_begin(&sha32);
		sha256_hash((unsigned char *)pUserName , uEncryptedUN, &sha32);
		sha256_end(vContentsHash, &sha32);
		if(memcmp(m_dbLastHeader->m_ContentsHash, vContentsHash, 32) != 0)
			{ SAFE_DELETE_ARRAY(pUserName); return PWE_INVALID_KEY; }

		sha256_begin(&sha32);
		sha256_hash((unsigned char *)pPassword , uEncryptedPsw, &sha32);
		sha256_end(vContentsHash, &sha32);
		if(memcmp(m_dbLastHeader->m_ContentsHash, vContentsHash, 32) != 0)
			{ SAFE_DELETE_ARRAY(pPassword); return PWE_INVALID_KEY; }*/

		pPd->m_strUserName = _UTF8ToString((UTF8_BYTE *)pUserName);
		SAFE_DELETE_ARRAY(pUserName);
		

		pPd->m_strPassword = _UTF8ToString((UTF8_BYTE *)pPassword);
		SAFE_DELETE_ARRAY(pPassword);
		UnlockEntryPassword(pPd);

	} 

	mem_erase(uFinalKey, 32);

	return PWE_SUCCESS;
}

int CPwManager::SaveDatabase(CString strName)
{
	UINT8 uFinalKey[32];
	sha256_ctx sha32;
	//CPwMaster m_dbLastHeader;
	//memcpy(&m_dbLastHeader,&m_dbLastHeader,sizeof(CPwMaster));

//	char *pVirtualFile = new char[uAllocated];
	
	m_dbLastHeader->m_KeyEncRounds = m_dwKeyEncRounds;

	// Make up the master key hash seed and the encryption IV
	m_random.GetRandomBuffer(m_dbLastHeader->m_MasterSeed, 16);
	m_random.GetRandomBuffer((BYTE *)m_dbLastHeader->m_EncryptionIV, 16);
	m_random.GetRandomBuffer(m_dbLastHeader->m_MasterSeed2, 32);

	// Skip the header, it will be written later
	if(_TransformMasterKey(m_dbLastHeader->m_MasterSeed2) == FALSE)
		{ return PWE_CRYPT_ERROR; }

	ProtectTransformedMasterKey(false);

	// Hash the master password with the generated hash salt
	sha256_begin(&sha32);
	sha256_hash(m_dbLastHeader->m_MasterSeed, 16, &sha32);
	sha256_hash(m_pTransformedMasterKey, 32, &sha32);
	sha256_end((unsigned char *)uFinalKey, &sha32);
	
	ProtectTransformedMasterKey(true);
	BOOL bSave = FALSE;
	CPasswordManager PwMM;
	PwMM.BeginSave();
	bSave = PwMM.Save(*m_dbLastHeader);
	if(!bSave)
	{
		PwMM.EndSave(bSave);	
		return PWE_FILEERROR_WRITE;
	}
//	PwMM.Add(m_dbLastHeader);
//	CPasswordManager PsM;
	POSITION Pos = m_pEntries->GetHeadPosition();
	while(Pos != NULL) 
	{
		CPasswordProfile * pPd= m_pEntries->GetNext(Pos);
		
		UnlockEntryPassword(pPd);
		SAFE_DELETE_ARRAY(pPd->m_pPassword);
		SAFE_DELETE_ARRAY(pPd->m_pUserName);
		pPd->m_pPassword = _StringToUTF8(pPd->m_strPassword);
		pPd->m_pUserName = _StringToUTF8(pPd->m_strUserName);
		int nPWLen = szlen((char *)(pPd->m_pPassword)); 
		int uAllPsw = (nPWLen + 16) - (nPWLen % 16) + 16;

		int nUNLen = szlen((char *)(pPd->m_pUserName));
		int uAllUser = (nUNLen + 16) - (nUNLen % 16) + 16;
		BYTE* pAllPsw = new BYTE[uAllPsw];
		BYTE* pAllUser = new BYTE[uAllUser];
	//	szcpy(pAllPsw,pPd->m_pPassword);
	//	szcpy(pAllUser,pPd->m_pUserName);
		
		LockEntryPassword(pPd);
		if(m_nAlgorithm == ALGO_AES)
		{
			CRijndael aes;
			if(aes.Init(CRijndael::CBC, CRijndael::EncryptDir, uFinalKey,
				CRijndael::Key32Bytes, m_dbLastHeader->m_EncryptionIV) != RIJNDAEL_SUCCESS)
			{
				//SAFE_DELETE_ARRAY(pVirtualFile);
				return PWE_CRYPT_ERROR;
			}

			pPd->m_nUNLen = static_cast<unsigned long>(aes.PadEncrypt(
				pPd->m_pUserName,szlen((char *)(pPd->m_pUserName)) + 1,
				pAllUser));
			pPd->m_nPswLen = static_cast<unsigned long>(aes.PadEncrypt(
				pPd->m_pPassword,szlen((char *)(pPd->m_pPassword)) + 1,
				pAllPsw));
		}
		else if(m_nAlgorithm == ALGO_TWOFISH)
		{
			CTwofish twofish;
			if(twofish.Init(uFinalKey, 32, m_dbLastHeader->m_EncryptionIV) == false)
			{
				return PWE_CRYPT_ERROR;
			}

			pPd->m_nUNLen = static_cast<unsigned long>(twofish.PadEncrypt(
				(UINT8 *)pPd->m_pUserName,
				szlen((char *)(pPd->m_pUserName)) + 1, pAllUser));
			pPd->m_nPswLen = static_cast<unsigned long>(twofish.PadEncrypt(
				pPd->m_pPassword,szlen((char *)(pPd->m_pPassword)) + 1,
				pAllPsw));
		}
		SAFE_DELETE_ARRAY(pPd->m_pPassword);
		pPd->m_pPassword = new BYTE[pPd->m_nPswLen];
		memcpy(pPd->m_pPassword,pAllPsw,pPd->m_nPswLen);
		SAFE_DELETE_ARRAY(pPd->m_pUserName);
		pPd->m_pUserName = new BYTE[pPd->m_nUNLen];
		memcpy(pPd->m_pUserName,pAllUser,pPd->m_nUNLen);
		bSave = PwMM.Add(*pPd);
		SAFE_DELETE_ARRAY(pPd->m_pPassword);
		SAFE_DELETE_ARRAY(pPd->m_pUserName);

		mem_erase((unsigned char *)pAllPsw,uAllPsw);
		SAFE_DELETE_ARRAY(pAllPsw);

		mem_erase((unsigned char *)pAllUser,uAllUser);
		SAFE_DELETE_ARRAY(pAllUser);
		if(!bSave)
			break;

	}// while (Pos != NULL);
	
//	sha256_begin(&sha32);
//	sha256_hash((unsigned char *)pVirtualFile + sizeof(PW_DBHEADER), pos - sizeof(PW_DBHEADER), &sha32);
//	sha256_end((unsigned char *)hdr.aContentsHash, &sha32);

	// Now we have everything required to build up the header
	
	// Generate m_pTransformedMasterKey from m_pMasterKey
	
	PwMM.EndSave(bSave);
	mem_erase(uFinalKey, 32);


	//memcpy(&m_dbLastHeader, &Pwm, sizeof(CPwMaster)); // Backup last database header


	return PWE_SUCCESS;
}
